16. LiveData Testing Basics
L5 P2 A05 LiveData Testing Basics V2
In this step, you'll finish your addNewTask_setsNewTaskEvent() test.
Step 1: Add InstantTaskExecutor
- Add the gradle dependency.
app/build.gradle
testImplementation "androidx.arch.core:core-testing:$archTestingVersion"
- Open
TasksViewModelTest.kt. - Add the
InstantTaskExecutorRuleinside theTasksViewModelTestclass:
TasksViewModelTest.kt
class TasksViewModelTest {
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
// Other codeā¦
}
Step 2: Add the LiveDataTestUtil.kt Class
You'll not create the LiveDataTestUtil class so you can use the getOrAwaitValue Kotlin extension function.
- Make a new Kotlin file called
LiveDataTestUtil.ktin yourtestsource set:
- Copy and paste this code there:
LiveDataTestUtil.kt
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun <T> LiveData<T>.getOrAwaitValue(
time: Long = 2,
timeUnit: TimeUnit = TimeUnit.SECONDS,
afterObserve: () -> Unit = {}
): T {
var data: T? = null
val latch = CountDownLatch(1)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data = o
latch.countDown()
this@getOrAwaitValue.removeObserver(this)
}
}
this.observeForever(observer)
try {
afterObserve.invoke()
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
throw TimeoutException("LiveData value was never set.")
}
} finally {
this.removeObserver(observer)
}
@Suppress("UNCHECKED_CAST")
return data as T
}
For a full explanation of what this class, check out this blog post.
As you write your own tests that test LiveData, you can similarly copy and use this class in your code.
Step 2: Use getOrAwaitValue to Write the Assertion
Let's use the getOrAwaitValue method and write an assert statement that checks that the newTaskEvent was triggered:
- Open
TaskViewModelTest.kt. - Get the
LiveDatavalue fornewTaskEventusinggetOrAwaitValue:
TasksViewModelTest.kt
val value = tasksViewModel.newTaskEvent.getOrAwaitValue()
- Assert that the value is not null:
TasksViewModelTest.kt
assertThat(value.getContentIfNotHandled(), (not(nullValue())))
The complete test should look like this:
TasksViewModelTest.kt
@Test
fun addNewTask_setsNewTaskEvent() {
// Given a fresh ViewModel
val tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())
// When adding a new task
tasksViewModel.addNewTask()
// Then the new task event is triggered
val value = tasksViewModel.newTaskEvent.getOrAwaitValue()
assertThat(
value.getContentIfNotHandled(), (not(nullValue()))
)
}
- Run your code and watch the test pass!